package restserver

import (
	"context"
	"errors"
	"fmt"
	"gitee.com/vrv_media/go-micro-framework/pkg/common/endpoint"
	utilNet "gitee.com/vrv_media/go-micro-framework/pkg/common/util/net"
	log "gitee.com/vrv_media/go-micro-framework/pkg/logger"
	"gitee.com/vrv_media/go-micro-framework/server/restserver/middlewares"
	"gitee.com/vrv_media/go-micro-framework/server/restserver/pprof"
	"gitee.com/vrv_media/go-micro-framework/server/restserver/validation"
	"github.com/gin-gonic/gin"
	ut "github.com/go-playground/universal-translator"
	socketio "github.com/googollee/go-socket.io"
	"github.com/penglongli/gin-metrics/ginmetrics"
	"net"
	"net/http"
	"net/url"
	"strings"
)

// Server wrapper for gin.Engine
type Server struct {
	*gin.Engine
	server   *http.Server
	address  string
	lis      net.Listener
	certFile string
	keyFile  string
	endpoint *url.URL
	err      error
	// 开发模式 默认值 debug
	mode string
	// 是否开启 安全连接
	enableTls bool
	// 是否开启 pprof接口, 默认不开启, 如果开启会自动添加 /debug/pprof 接口
	enableProfiling bool
	// 是否开启 链路追踪 默认不开启
	enableTracing bool
	// 是否开启 metrics 接口, 默认不开启, 如果开启会自动添加 /metrics 接口
	enableMetrics bool
	// 启用默认的健康检查
	enableDefaultHealth bool
	// 中间件
	//middlewares 客户自定义的拦截器
	middlewares []gin.HandlerFunc
	// 翻译器
	transName   string        // 翻译器名称，默认zh
	trans       ut.Translator // 翻译器的结构数据
	serviceName string
	// 是否启动socketIo
	enableSocketIoServer bool
	socketIoServer       *socketio.Server
}

func NewServer(opts ...ServerOption) *Server {
	srv := &Server{
		address:              ":0",
		mode:                 gin.DebugMode,
		enableProfiling:      false,
		enableTracing:        false,
		enableMetrics:        false,
		enableTls:            false,
		enableSocketIoServer: false,
		enableDefaultHealth:  false,
		Engine:               gin.Default(),
		transName:            "en",
		serviceName:          "gmicro",
		middlewares:          make([]gin.HandlerFunc, 0),
	}
	for _, o := range opts {
		o(srv)
	}
	err := srv.buildServer()
	if err != nil {
		panic(err)
	}
	return srv
}

func (s *Server) buildServer() error {
	// 默认添加跨域和recovery的拦截器
	s.Use(middlewares.CorsHandler())
	s.Use(middlewares.RecoveryHandler())

	// 开启链路追踪
	if s.enableTracing {
		s.Use(middlewares.TracingHandler(s.serviceName))
	}
	if len(s.middlewares) > 0 {
		s.Use(s.middlewares...)
	}
	// 设置开发模式, 打印路由信息
	if s.mode != gin.DebugMode && s.mode != gin.ReleaseMode && s.mode != gin.TestMode {
		return errors.New("mode must be one of debug/release/test")
	}
	gin.SetMode(s.mode)

	// 修改 gin 调试日志输出格式
	gin.DebugPrintRouteFunc = func(httpMethod, absolutePath, handlerName string, nuHandlers int) {
		handlerName = strings.SplitN(handlerName, ".", 2)[0]
		log.InfoF("%-6s %-s --> %s(%d handlers)", httpMethod, absolutePath, handlerName, nuHandlers)
	}
	err := s.initTrans(s.transName)
	if err != nil {
		panic(fmt.Sprintf("init translator error: %s", err.Error()))
	}

	// 注册 mobile 验证器
	validation.RegisterMobile(s.trans)

	// 根据配置初始化 pprof 路由
	if s.enableProfiling {
		pprof.Register(s.Engine)
	}

	// 开启 普罗米修斯监控
	if s.enableMetrics {
		m := ginmetrics.GetMonitor() // gin-metrics 可以自动 收集相关信息 并且开启 /metrics 的 接口

		// +optional set metric path, default /debug/metrics
		m.SetMetricPath("/metrics")
		// 慢请求的时间, default 5s
		m.SetSlowTime(5)
		// +optional set request duration, default {0.1, 0.3, 1.2, 5, 10}
		// used to p95, p99
		m.SetDuration([]float64{0.1, 0.3, 1.2, 5, 10})
		// set middleware for gin
		m.Use(s.Engine)
	}

	// 启动socketIo
	if s.enableSocketIoServer && s.socketIoServer == nil {
		s.socketIoServer, err = socketio.NewServer(nil)
		if err != nil {
			return err
		}
	}

	// 注册默认的健康检查
	if s.enableDefaultHealth {
		s.Engine.GET("/health", func(c *gin.Context) {
			c.JSON(http.StatusOK, gin.H{
				"code":    http.StatusOK,
				"success": true,
			})
		})
	}

	return nil

	return nil
}
func (s *Server) RegistryWebsocket(relativePath string) {
	s.Engine.Any(relativePath, gin.WrapH(s.socketIoServer))
}

func (s *Server) Translator() ut.Translator {
	return s.trans
}

func (s *Server) SocketIoServer() *socketio.Server {
	return s.socketIoServer
}

// Start rest server
func (s *Server) Start(ctx context.Context) error {
	log.InfoF("[gin] start rest server on %s", s.address)
	s.server = &http.Server{
		Addr:    s.address,
		Handler: s.Engine,
	}

	// 在 Gin 框架中，SetTrustedProxies 方法是 gin.Engine 结构体的一个方法，用于设置信任的代理服务器，
	// 以便在处理 HTTP 请求时跳过这些代理服务器的 IP 地址。将参数设置为 nil 表示没有信任的代理服务器需要跳过，这可能会影响请求的处理方式
	_ = s.SetTrustedProxies(nil)
	//err = s.Run(fmt.Sprintf(":%d", s.port))
	// http.ErrServerClosed 表示服务已经优雅退出了
	var err error
	if s.enableTls {
		err = s.server.ServeTLS(s.lis, s.certFile, s.keyFile)
	} else {
		err = s.server.Serve(s.lis)
	}
	if err != nil && !errors.Is(err, http.ErrServerClosed) {
		return err
	}
	log.InfoF("server listening,port : %d", s.lis.Addr().String())
	return nil
}

func (s *Server) Stop(ctx context.Context) error {
	if err := s.server.Shutdown(ctx); err != nil {
		log.ErrorF("shutdown rest server error: %s", err.Error())
		return err
	}
	log.Info("rest server stopped")
	return nil
}

func (s *Server) Endpoint() (*url.URL, error) {
	if err := s.listenAndEndpoint(); err != nil {
		return nil, err
	}
	return s.endpoint, nil
}

func (s *Server) listenAndEndpoint() error {
	if s.lis == nil {
		lis, err := net.Listen("tcp", s.address)
		if err != nil {
			return err
		}
		s.lis = lis
	}
	if s.endpoint == nil {
		addr, err := utilNet.Extract(s.address, s.lis)
		if err != nil {
			s.err = err
			_ = s.lis.Close()
			return err
		}
		s.endpoint = endpoint.NewEndpoint(endpoint.Scheme("http", s.enableTls), addr)
	}
	return s.err
}
